跳到主要内容

Git 的 HEAD 指针

这部分转载自 Git-你好, HEAD 同学

Git 的 HEAD 指针

Head 指针可以指向快照节点也可以指向 branch。当指向 branch 时提交后会和 branch指针一起向后移动,当不指向 branch提交时时则会在一个 detached(游离)状态。

HEAD 在哪?HEAD 是谁?

第一步,我们先要去找到 HEAD。找之前,先考大家一个问题:

Git 是怎么和项目联系起来的呢?

在执行第一个 git 命令操作 git init 的时候,在项目的根目录下,创建了一个 .git 文件夹, 此文件是隐藏文件

打开 .git,可看到如下内容:

.git 文件中存储 Git 对这个项目进行版本控制的所有信息,同时可以发现这里面有一个文件叫做 HEAD

打开这个文件可以发现它是指向了另一个文件的应用,于是找的 refs/heads/master 打开(如果刚创建的目录是不存在这个文件的,得有 “历史” 记录才行)

可以通过 git show 命令来查看 HEAD 指针目前指向什么。

HEAD 的本质是什么?

通过 git log 查看,可以发现是上面 master 文件的内容是 master 分支最新的提交。

所以目前 HEAD 文件指向的内容是传递顺序是这样的:

HEAD -> refs/heads/master -> b003ebaff6916c3aa86b2a51bfea15b52686bbc0

得出了一个结论,HEAD 的本质不是提向分支,而是指向 commit 提交。

问题又来了:

  • HEAD 为什么要通过 refs/heads/master 中转一下,而不是直接指向 master 分支的提交?
  • HEAD 可以直接指向提交吗?

解释以上问题,需要知道 refs/heads/ 文件夹存储的内容是当前项目所有分支的头指针,每个分支的头指针都指向该分支的最新提交。

从上图看,三个分支的头指针指向的提交都不同,HEAD直接指向提交毫无问题。

但是此时出现一个 dev 分支,刚从 master 检出,头指针和 master 相同,HEAD直接指向提交的话,怎么知道,当前工作分支是 master 还是 dev 呢?

此时 HEAD 文件的内容就非常有意义了:

所以,HEAD 通过先指向分支的头指针,再指向提交的意义就是表明当前所处的分支。

关于第二个问题,答案是肯定的,但是会进入一种特殊的状态 detached HEAD。

detached HEAD

使用 git checkout <commit id> 成功的进入了

detached HEAD 状态:

此时的 HEAD 文件内容,不再指向分支的头指针,而是直接指向了提交。

得出结论,当 HEAD 指针直接指向提交时,就会导致 detached HEAD 状态。在这个状态下,如果创建了新提交,新提交不属于任何分支。相对应的,现存的所有分支也不会受 detached HEAD 状态提交的影响。

这个状态并不是坏事,在某些特殊的场景下你可能会需要它。

例如:

排查问题的时候,checkout 到怀疑的 commit 点上去做些测试,detached HEAD 会保护你的现有分支不受影响,测试完了不想保存直接 checkout 到其他地方,可以放弃修改,想保存修改,可以创建一个 git checkout -b <new-branch-name> 新分支保存。

除了 git checkout <commit id>,还有一个命令可以进入 detached HEAD 状态。

# HEAD 直接脱离分支头指针,指向分支头指针指向的 commit
git checkout --detach

移动分支到 detached

移动已存在的分支到 detached 状态的分支

git branch -f master C2

这个时候 master 分支以前的快照 C3就变成了 detached 状态了